home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / et / et-2_2.lha / et2.2 / src / GapText.C < prev    next >
C/C++ Source or Header  |  1990-12-06  |  12KB  |  600 lines

  1. //$GapText,GapTextIter$
  2. #include "GapText.h" 
  3. #include "RegularExp.h"
  4. #include "Port.h"
  5. #include "Error.h"
  6.  
  7. const int cShrinkFactor = 2,
  8.       cMaxOutput    = 500,
  9.       cInitialSize  = 16;
  10. char *cMemOverflow= "memory overflow",
  11.      *cGapTextName= "CheckPtr";
  12.  
  13. static TextChanges changeRec;
  14.  
  15. //---- GapText -----------------------------------------------------------------
  16.  
  17. MetaImpl(GapText, (T(size), T(length), T(part1len), T(gaplen),
  18.             TV(body, part1len), TV(body2, part2len), TP(font), 0));
  19.  
  20. void GapText::MoveGap(int to)
  21. {
  22.     if (to == part1len)
  23.     return;
  24.  
  25.     if (part1len > to)
  26.     BCOPY(body+to, body+to+gaplen, part1len-to);
  27.     else 
  28.     BCOPY(body+part1len+gaplen, body+part1len, to-part1len);
  29.  
  30.     part1len= to; 
  31. }            
  32.  
  33. void GapText::CopyTo(byte *dst, int from, int to)
  34. {
  35.     // Copy Text between 'from' and 'to' to 'dst'
  36.  
  37.     int beforegap= max(0, part1len-from) - max(0, part1len-to);
  38.     int aftergap = max(0, to - part1len) - max(0, from-part1len);
  39.  
  40.     if (beforegap) 
  41.     BCOPY(body+from, dst, beforegap);
  42.     if (aftergap)
  43.     BCOPY(part2body+max(part1len, from), dst+beforegap, aftergap);
  44. }
  45.  
  46. void GapText::Expand(int to, int moveto)
  47.     // Expand size of Text to 'to'
  48.     byte *pos, *part2;
  49.  
  50.     if (to == 0)
  51.     to= size * 2;
  52.  
  53.     if (to < size) 
  54.     return;
  55.  
  56.     if (moveto > length)
  57.     moveto= length;
  58.  
  59.     size= to;
  60.     pos= new byte[size];
  61.     CheckPtr(pos);
  62.     part2= pos + size -length;
  63.  
  64.     if (moveto < part1len) {
  65.     BCOPY(body, pos, moveto);
  66.     BCOPY(body + moveto, part2 + moveto, part1len - moveto);
  67.     BCOPY(part2body + part1len, part2 + part1len, length -part1len);
  68.     } else {
  69.     BCOPY(body, pos, part1len);
  70.     BCOPY(part2body + part1len, pos + part1len, moveto - part1len);
  71.     BCOPY(part2body + moveto, part2 + moveto, length - moveto);
  72.     }
  73.  
  74.     delete body;
  75.     body= pos;
  76.  
  77.     Update(moveto);
  78. }
  79.  
  80. void GapText::Shrink(int to)
  81.     // Reduce size of Text to 'to'
  82.     // If to = 0 then size = size / cShrinkFactor + 1
  83.  
  84.     byte *pos;
  85.  
  86.     if ((to == 0) || (to < length))
  87.     to= size / cShrinkFactor + 1;
  88.  
  89.     if ( (to > size) || (to < length) ) 
  90.     return;
  91.  
  92.     size= to;
  93.  
  94.     pos= new byte[size];
  95.     CheckPtr(pos);
  96.  
  97.     BCOPY(body, pos, part1len);
  98.     BCOPY(body+part1len+gaplen, pos+part1len, length-part1len);
  99.  
  100.     delete body;
  101.     body= pos;
  102.  
  103.     Update(length);
  104. }
  105.  
  106. GapText::GapText(int s, FontPtr fd)
  107.     size= max(cInitialSize, s);
  108.     body= new byte[size];
  109.     CheckPtr(body);
  110.     Init(0, fd);
  111. }
  112.  
  113. GapText::GapText(byte *buf, int len, bool ic, FontPtr fd)
  114. {   
  115.     if (len < 0)
  116.     len= strlen((char*)buf);
  117.     size= max(cInitialSize, len);
  118.     if (ic)
  119.     body= buf;
  120.     else {
  121.     body= new byte[size];
  122.     CheckPtr(body);
  123.     BCOPY(buf, body, len);
  124.     }
  125.     Init(len, fd);
  126. }
  127.  
  128. void GapText::Init(int l, FontPtr fd)
  129. {
  130.     length= l;
  131.     Update(l);
  132.     font= fd;
  133.     ink= ePatBlack;
  134.     SetTabWidth(fd->Width(' ')*8);
  135. }
  136.  
  137. GapText::~GapText()
  138. {
  139.     SafeDelete(body);
  140.     part2body= 0;
  141. }
  142.  
  143. void GapText::Paste(TextPtr paste,int from,int to)
  144. {
  145.     if (!CheckRange(length,from,to))
  146.     return;
  147.  
  148.     GapText *ft;
  149.     byte *buf= 0;
  150.  
  151.     if (!paste->IsKindOf(GapText)) {  // convert the text into a GapText
  152.     int s = paste->Size();
  153.     buf= new byte[s+1];
  154.     paste->CopyInStr(buf, s+1, 0, s);
  155.     ft= new GapText(buf, s, TRUE);
  156.     } else
  157.     ft= (GapText *)paste;
  158.  
  159.     int shift= ft->length - (to - from);
  160.  
  161.     if (HighWaterMark(shift))
  162.     Expand(GrowBy(size + shift), from);
  163.     else
  164.     MoveGap(from);
  165.  
  166.     ft->CopyTo(body+from, 0, ft->length);
  167.  
  168.     length    += shift;
  169.     gaplen    -= shift;
  170.     part1len  += ft->length;
  171.     part2body -= shift;
  172.     part2len= length - part1len;
  173.     body2= part2body + part1len;
  174.  
  175.     if (LowWaterMark())
  176.     Shrink();   
  177.     if (buf)
  178.     delete ft;
  179.     Text::Paste(paste, from, to);
  180.     Send(cIdNone, eTextReplaced, changeRec(from, to, paste->Size()));
  181. }
  182.  
  183. void GapText::Cut(int from,int to)
  184. {
  185.     int shift= to - from;
  186.  
  187.     if (!CheckRange(length, from, to))
  188.     return;
  189.  
  190.     if (from <= part1len && to >= part1len) // Gap is in between
  191.     part1len= from;
  192.     else  
  193.     MoveGap(from); 
  194.     length -= shift;
  195.     gaplen += shift;
  196.     part2body += shift;
  197.     part2len= length - part1len;
  198.     body2= part2body + part1len;
  199.  
  200.     if (LowWaterMark())
  201.     Shrink();
  202.  
  203.     Text::Cut(from,to);   
  204.     Send(cIdNone, eTextDeleted, changeRec(from, to));     
  205. }  
  206.  
  207. void GapText::Copy(Text *save,int from, int to)
  208. {
  209.     if (!CheckRange(length,from,to) || (save == 0))
  210.     return;
  211.  
  212.     if (!save->IsKindOf(GapText)){ // convert
  213.     int s= to -from ;
  214.     byte *buf= new byte[s+1];
  215.     CopyTo(buf, from, to); 
  216.     buf[to-from]= '\0';
  217.     save->ReplaceWithStr(buf,s); 
  218.     delete buf;
  219.     return;
  220.     }
  221.  
  222.     GapText *ft= (GapText*) save;
  223.     int nSize= to - from;
  224.  
  225.     ft->Empty();
  226.  
  227.     if (ft->size < nSize) 
  228.     ft->Expand(nSize, 0);
  229.  
  230.     CopyTo(ft->body, from, to);
  231.  
  232.     ft->length= to-from;
  233.     ft->Update(to-from);
  234. }
  235.  
  236. void GapText::CopyInStr(byte *str,int strsize,int from, int to)
  237. {
  238.     if (!CheckRange(length,from,to) || (str == 0))
  239.     return;
  240.     to= min(to,from + strsize-1);   
  241.     CopyTo(str, from, to);
  242.     str[to-from] = '\0';
  243. }
  244.  
  245. void GapText::ReplaceWithStr(byte *str, int len)
  246. {
  247.     if (len < 0)
  248.     len= strlen((char*)str);
  249.     Empty();
  250.     if (size < len) 
  251.     Expand(len,0);
  252.     BCOPY(str, body, len);
  253.     length= len;
  254.     Update(len);
  255. }
  256.  
  257. void GapText::SetFStringVL(char *fmt, va_list ap)
  258. {
  259.     Empty();
  260.     char *buf= strvprintf(fmt, ap);
  261.     int l= strlen(buf); 
  262.     if (size < l) 
  263.     Expand(l,0);
  264.     BCOPY((byte*)buf, body, l);
  265.     length= l;
  266.     Update(l);
  267.     SafeDelete(buf);
  268. }
  269.  
  270. int GapText::Search(RegularExp *rex, int *nMatched, int start, int range, 
  271.                          bool forward)
  272. {
  273.     int pos;
  274.  
  275.     if (forward) 
  276.     pos= rex->SearchForward2((char*)body, part1len,
  277.                         (char*)(body+part1len+gaplen), 
  278.             length-part1len, start, range, 0, nMatched);
  279.     else {
  280.     // BUG in RegularExp::SearchBackward2 ??
  281.     MoveGap(length);
  282.     pos= rex->SearchBackward((char*)body, nMatched, start, length, range, 0);
  283.     } 
  284.     return pos;
  285. }
  286.  
  287. byte *GapText::GetTextAt(int from, int to)
  288. {    
  289.     if (!CheckRange(length,from,to))
  290.     return 0;
  291.  
  292.     if ((part1len < to) && (part1len >= from))
  293.     // Gap is in between 
  294.     if ( part1len > (( to + from) >> 1) )   
  295.         MoveGap(to);
  296.     else
  297.         MoveGap(from);
  298.  
  299.     if (part1len < from) 
  300.     return &part2body[from];
  301.     return &body[from];
  302. }
  303.  
  304. TextPtr GapText::Save(int from, int to)
  305. {
  306.     if (!CheckRange(length,from,to))
  307.     return 0;
  308.  
  309.     GapText* t= new GapText(to-from);
  310.     Copy(t, from, to);
  311.     return t;
  312. }
  313.  
  314. void GapText::Insert(byte c, int from, int to)
  315. {
  316.     int shift= 1 - (to - from);
  317.  
  318.     if (!CheckRange(length,from,to))
  319.     return;
  320.  
  321.     if (HighWaterMark(shift))
  322.     Expand(GrowBy(size+shift), from);
  323.     else     
  324.     MoveGap(from);
  325.     body[from] = c;
  326.  
  327.     length    += shift;
  328.     gaplen    -= shift;
  329.     part1len  += shift;
  330.     part2body -= shift;
  331.     part2len= length - part1len;
  332.     body2= part2body + part1len;
  333.  
  334.     if (LowWaterMark())
  335.     Shrink();
  336.  
  337.     Text::Insert(c, from, to);
  338.     Send(cIdNone, eTextReplaced, changeRec(from, to, 1));     
  339. }
  340.  
  341. byte& GapText::operator[](int i)
  342. {
  343.     //----> should notify about possible changes but how?? 
  344.     i= min(i, length-1);
  345.     if (i < part1len)
  346.     return body[i];
  347.     return part2body[i];
  348. }
  349.  
  350. void GapText::Empty(int initSize)                                         
  351. {
  352.     if (initSize > 0) {
  353.     delete body;
  354.     body= new byte[size= initSize];
  355.     CheckPtr(body);
  356.     }
  357.     length= 0;
  358.     Update(0);
  359. }
  360.  
  361. bool GapText::IsEqual(ObjPtr text)                                         
  362. {
  363.     if (!text->IsKindOf(GapText))
  364.     return FALSE;
  365.     GapText *t= (GapText *) text; 
  366.  
  367.     if (length != t->length) 
  368.     return FALSE;
  369.  
  370.     MoveGap(length);
  371.     t->MoveGap(t->length);
  372.     return (strncmp((char*)body, (char*)t->body, length) == 0);
  373. }
  374.  
  375. int GapText::Size()
  376.     return length; 
  377. }                                         
  378.  
  379. bool GapText::IsEmpty()
  380. {   
  381.     return length == 0; 
  382. }
  383.  
  384. unsigned long GapText::Hash()                                         
  385. {
  386.     register unsigned long hash;
  387.     register byte *p;
  388.  
  389.     for (hash= 0, p= body; p < body+part1len; p++)
  390.     hash= (hash << 1) ^ *p;
  391.     for (p= body+part1len+gaplen; p < body+size; p++)
  392.     hash= (hash << 1) ^ *p;
  393.     return hash;
  394. }
  395.  
  396. bool GapText::IsEqualStr(byte *t)                                         
  397. {
  398.     if (length != strlen((char*)t)) 
  399.     return FALSE;
  400.     MoveGap(length);
  401.     return strncmp((char*)body, (char*)t, length) == 0;
  402. }
  403.  
  404. void GapText::Dump()
  405. {   
  406.     int i;
  407.     cerr << "size : " << size << "\n";
  408.     cerr << "length  : " << length << "\n";
  409.     cerr << "part1len     : " << part1len << "\n";
  410.     cerr << "gaplen  : " << gaplen << "\n";
  411.     cerr << "part2body-body    : " << int(part2body-body) << "\n";
  412.     cerr << "body  : ";
  413.     for (i=0 ; i < size ; i++){
  414.     if (i == part1len )
  415.         cerr << "[";
  416.     if (i == (part1len + gaplen))
  417.         cerr << "]";
  418.     if ((body[i]>= ' ') && (body[i] <='~'))
  419.         cerr.put(body[i]);
  420.     else
  421.         cerr << ".";
  422.     }
  423.     cerr << "\n" ;
  424. }
  425.  
  426. TextIter *GapText::MakeIterator(int from, int to)
  427. {
  428.     return new GapTextIter(this,from,to);
  429. }
  430.  
  431. ostream& GapText::PrintOn(ostream& s)
  432. {
  433.     Text::PrintOn(s);
  434.     s << font SP << ink SP; 
  435.     MoveGap(length);
  436.     return PrintString(s, body, length);
  437. }
  438.  
  439. istream& GapText::ReadFrom(istream& s)
  440. {
  441.     Text::ReadFrom(s);
  442.     s >> font >> ink;
  443.     SafeDelete(body);
  444.     ReadString(s, &body, &length);
  445.     size= length;
  446.     Update(length);
  447.     return s;
  448. }
  449.  
  450. ostream& GapText::PrintOnAsPureText(ostream& s)
  451. {
  452.     register int i;
  453.     for (i= 0; i < length; i++)
  454.     s.put(CharAt(i));
  455.     return s;
  456. }
  457.  
  458. istream& GapText::ReadFromAsPureText(istream& s, long sizeHint)
  459. {
  460.     char ch;
  461.  
  462.     if (sizeHint > 0 && ((int)(sizeHint - size)) > 0)
  463.     Expand(GrowBy((int)sizeHint + 50));
  464.     if (body == 0)
  465.     body= new byte[size= 1024];
  466.     length= 0;
  467.  
  468.     while (s.get(ch)) {
  469.     if (length >= size){
  470.         part2body= body ;
  471.         body= new byte[size= (size+1)*2];
  472.         CheckPtr(body);
  473.         BCOPY(part2body, body, length);
  474.         delete part2body;
  475.     }
  476.     body[length++]= ch;
  477.     }
  478.  
  479.     Update(length);
  480.  
  481.     if (!s.eof())
  482.     Error("ReadFromAsPureText", "something strange happended");
  483.     return s;
  484. }
  485.  
  486. int GapText::TextWidth(int from, int to)
  487. {
  488.     if (!CheckRange(length, from ,to))
  489.     return 0;
  490.  
  491.     register int i, w= 0;
  492.     register byte c;
  493.     for (i= from; i < to; i++) {
  494.     if ((c= CharAt(i)) == '\t') 
  495.         w+= Tabulate(w); 
  496.     else
  497.         w+= font->Width(c);
  498.     }
  499.     return w;
  500. }
  501.  
  502. void GapText::DrawText(int from, int to, Rectangle)
  503. {
  504.     if (!CheckRange(length, from ,to))
  505.     return;
  506.  
  507.     Point start= GrGetTextPos();
  508.     register int i;
  509.     register byte c;
  510.     SetDrawingState(from);
  511.     for (i= from; i < to; i++)
  512.     if ((c= CharAt(i)) == '\t') 
  513.         GrTextAdvance(Tabulate(GrGetTextPos().x-start.x)); 
  514.     else
  515.         GrDrawChar(c);
  516.  
  517. //---- GapTextIter -------------------------------------------------------------
  518.  
  519. GapTextIter::GapTextIter(Text *s, int from, int to) : TextIter(s, from, to)
  520. {
  521.     if (!s->IsKindOf(GapText))
  522.     Error("GapTextIter::Error", "GapText expected (%s received)", s->ClassName());
  523.     font= s->GetFont();
  524.  
  525. int GapTextIter::operator()()
  526.     return (ce == upto ? cEOT : ((GapText*)ct)->CharAt(ce++)); 
  527. }
  528.  
  529. int GapTextIter::operator()(int *w, LineDesc *ld)  
  530. {
  531.     register GapTextPtr pt= GapTextPtr(ct);
  532.     int ch;
  533.  
  534.     if (ld) 
  535.     ld->FromFont(font);
  536.     *w= 0;
  537.     if (ce == upto )
  538.     return cEOT;
  539.     ch= GapTextPtr(ct)->CharAt(ce++);
  540.     *w= font->Width(ch);
  541.     return ch;
  542. }
  543.  
  544. int GapTextIter::Line(LineDesc *ld)
  545. {
  546.     register GapTextPtr pt = GapTextPtr(ct);
  547.     if (ld) 
  548.     ld->FromFont(font);
  549.     unget= ce;
  550.     if (ce == upto) {
  551.     // special case if last line is empty
  552.     int last= GapTextPtr(ct)->CharAt(ce-1);
  553.     ce++;
  554.     if (last == '\n' || last == '\r')
  555.         return upto;
  556.     }
  557.     if (ce > upto)
  558.     return cEOT;
  559.  
  560.     while (ce < upto) {
  561.     int ch= GapTextPtr(ct)->CharAt(ce++);
  562.     if (ch == '\n' || ch == '\r')
  563.         break;
  564.     }
  565.     return ce;
  566. }
  567.  
  568. int GapTextIter::Token(int *w, LineDesc *ld)
  569. {
  570.     unget= ce;
  571.     register GapTextPtr pt= GapTextPtr(ct);
  572.  
  573.     *w= 0;
  574.     if (ld) 
  575.     ld->FromFont(font);
  576.  
  577.     if (ce >= upto)
  578.     return cEOT;
  579.  
  580.     register int ch= pt->CharAt(ce);
  581.     if (Isspace(ch)) {
  582.     *w= font->Width(ch);
  583.     ce++;
  584.     return ch;
  585.     }
  586.     while (ce < upto && !Isspace(pt->CharAt(ce))) {
  587.     ch= pt->CharAt(ce++);
  588.     *w += font->Width(ch);
  589.     }
  590.  
  591.     return ch;
  592. }
  593.